﻿Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Reflection
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Design
Imports System.Workflow.ComponentModel.Serialization

Namespace System.Workflow.ComponentModel.Compiler
    Public Class DependencyObjectValidator
        Inherits Validator
        ' Methods
        Public Overrides Function Validate(ByVal manager As ValidationManager, ByVal obj As Object) As ValidationErrorCollection
            If (manager Is Nothing) Then
                Throw New ArgumentNullException("manager")
            End If
            If (obj Is Nothing) Then
                Throw New ArgumentNullException("obj")
            End If
            Dim errors As ValidationErrorCollection = MyBase.Validate(manager, obj)
            Dim dependencyObject As DependencyObject = [TryCast](obj,DependencyObject)
            If (dependencyObject Is Nothing) Then
                Throw New ArgumentException(SR.GetString("Error_UnexpectedArgumentType", New Object() { GetType(DependencyObject).FullName }), "obj")
            End If
            Dim list As New ArrayList
            Dim property As DependencyProperty
            For Each property In DependencyProperty.FromType(dependencyObject.GetType)
                If Not [property].IsAttached Then
                    list.Add([property])
                End If
            Next
            Dim property2 As DependencyProperty
            For Each property2 In dependencyObject.MetaDependencyProperties
                If (property2.IsAttached AndAlso (obj.GetType.GetProperty(property2.Name, (BindingFlags.Public Or BindingFlags.Instance)) Is Nothing)) Then
                    list.Add(property2)
                End If
            Next
            Dim property3 As DependencyProperty
            For Each property3 In list
                Dim attributes As Object() = property3.DefaultMetadata.GetAttributes(GetType(ValidationOptionAttribute))
                If (If((attributes.Length > 0), DirectCast(attributes(0), ValidationOptionAttribute).ValidationOption, ValidationOption.Optional) <> ValidationOption.None) Then
                    errors.AddRange(Me.ValidateDependencyProperty(dependencyObject, property3, manager))
                End If
            Next
            Return errors
        End Function

        Private Function ValidateDependencyProperty(ByVal dependencyObject As DependencyObject, ByVal dependencyProperty As DependencyProperty, ByVal manager As ValidationManager) As ValidationErrorCollection
            Dim errors As New ValidationErrorCollection
            Dim attributes As Attribute() = dependencyProperty.DefaultMetadata.GetAttributes(GetType(ValidationOptionAttribute))
            Dim option As ValidationOption = If((attributes.Length > 0), DirectCast(attributes(0), ValidationOptionAttribute).ValidationOption, ValidationOption.Optional)
            Dim propertyOwner As Activity = [TryCast](manager.Context.Item(GetType(Activity)),Activity)
            If (propertyOwner Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("Error_ContextStackItemMissing", New Object() { GetType(Activity).FullName }))
            End If
            Dim context As New PropertyValidationContext(propertyOwner, dependencyProperty)
            manager.Context.Push(context)
            Try 
                If (Not dependencyProperty.DefaultMetadata.DefaultValue Is Nothing) Then
                    If (Not dependencyProperty.PropertyType.IsValueType AndAlso (Not dependencyProperty.PropertyType Is GetType(String))) Then
                        errors.Add(New ValidationError(SR.GetString("Error_PropertyDefaultIsReference", New Object() { dependencyProperty.Name }), &H1A8))
                    ElseIf Not dependencyProperty.PropertyType.IsAssignableFrom(dependencyProperty.DefaultMetadata.DefaultValue.GetType) Then
                        errors.Add(New ValidationError(SR.GetString("Error_PropertyDefaultTypeMismatch", New Object() { dependencyProperty.Name, dependencyProperty.PropertyType.FullName, dependencyProperty.DefaultMetadata.DefaultValue.GetType.FullName }), &H1A9))
                    End If
                End If
                Dim propValue As Object = Nothing
                If dependencyObject.IsBindingSet(dependencyProperty) Then
                    propValue = dependencyObject.GetBinding(dependencyProperty)
                ElseIf Not dependencyProperty.IsEvent Then
                    propValue = dependencyObject.GetValue(dependencyProperty)
                End If
                If ((propValue Is Nothing) OrElse (propValue Is dependencyProperty.DefaultMetadata.DefaultValue)) Then
                    If dependencyProperty.IsEvent Then
                        propValue = dependencyObject.GetHandler(dependencyProperty)
                        If (propValue Is Nothing) Then
                            propValue = WorkflowMarkupSerializationHelpers.GetEventHandlerName(dependencyObject, dependencyProperty.Name)
                        End If
                        If (TypeOf propValue Is String AndAlso Not String.IsNullOrEmpty(CStr(propValue))) Then
                            errors.AddRange(Me.ValidateEvent(propertyOwner, dependencyProperty, propValue, manager))
                        End If
                    Else
                        propValue = dependencyObject.GetValue(dependencyProperty)
                    End If
                End If
                Dim flag As Boolean = ((Not propertyOwner.Parent Is Nothing) OrElse (TypeOf propertyOwner Is CompositeActivity AndAlso (DirectCast(propertyOwner, CompositeActivity).EnabledActivities.Count <> 0)))
                If ((([option] = ValidationOption.Required) AndAlso ((propValue Is Nothing) OrElse (TypeOf propValue Is String AndAlso String.IsNullOrEmpty(CStr(propValue))))) AndAlso (dependencyProperty.DefaultMetadata.IsMetaProperty AndAlso flag)) Then
                    errors.Add(ValidationError.GetNotSetValidationError(MyBase.GetFullPropertyName(manager)))
                    Return errors
                End If
                If (propValue Is Nothing) Then
                    Return errors
                End If
                If TypeOf propValue Is IList Then
                    Dim context2 As New PropertyValidationContext(propValue, Nothing, String.Empty)
                    manager.Context.Push(context2)
                    Try 
                        Dim obj3 As Object
                        For Each obj3 In DirectCast(propValue, IList)
                            errors.AddRange(ValidationHelpers.ValidateObject(manager, obj3))
                        Next
                        Return errors
                    Finally
                        manager.Context.Pop
                    End Try
                End If
                If (Not dependencyProperty.ValidatorType Is Nothing) Then
                    Dim validator As Validator = Nothing
                    Try 
                        validator = [TryCast](Activator.CreateInstance(dependencyProperty.ValidatorType),Validator)
                        If (validator Is Nothing) Then
                            errors.Add(New ValidationError(SR.GetString("Error_CreateValidator", New Object() { dependencyProperty.ValidatorType.FullName }), &H106))
                            Return errors
                        End If
                        errors.AddRange(validator.Validate(manager, propValue))
                        Return errors
                    Catch obj1 As Object
                        errors.Add(New ValidationError(SR.GetString("Error_CreateValidator", New Object() { dependencyProperty.ValidatorType.FullName }), &H106))
                        Return errors
                    End Try
                End If
                errors.AddRange(ValidationHelpers.ValidateObject(manager, propValue))
            Finally
                manager.Context.Pop
            End Try
            Return errors
        End Function

        Private Function ValidateEvent(ByVal activity As Activity, ByVal dependencyProperty As DependencyProperty, ByVal propValue As Object, ByVal manager As ValidationManager) As ValidationErrorCollection
            Dim errors As New ValidationErrorCollection
            If (TypeOf propValue Is String AndAlso Not String.IsNullOrEmpty(CStr(propValue))) Then
                Dim flag As Boolean = False
                Dim type As Type = Nothing
                Dim rootActivity As Activity = Helpers.GetRootActivity(activity)
                Dim enclosingActivity As Activity = Helpers.GetEnclosingActivity(activity)
                Dim str As String = [TryCast](rootActivity.GetValue(WorkflowMarkupSerializer.XClassProperty),String)
                If ((rootActivity Is enclosingActivity) AndAlso Not String.IsNullOrEmpty(str)) Then
                    Dim service As ITypeProvider = [TryCast](manager.GetService(GetType(ITypeProvider)),ITypeProvider)
                    If (service Is Nothing) Then
                        Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(ITypeProvider).FullName }))
                    End If
                    type = service.GetType(str)
                Else
                    type = enclosingActivity.GetType
                End If
                If (Not type Is Nothing) Then
                    Dim method As MethodInfo = dependencyProperty.PropertyType.GetMethod("Invoke")
                    If (Not method Is Nothing) Then
                        Dim list As New List([Of] Type)
                        Dim info2 As ParameterInfo
                        For Each info2 In method.GetParameters
                            list.Add(info2.ParameterType)
                        Next
                        Dim info3 As MethodInfo = Helpers.GetMethodExactMatch(type, [TryCast](propValue,String), (BindingFlags.FlattenHierarchy Or (BindingFlags.NonPublic Or (BindingFlags.Public Or (BindingFlags.Static Or BindingFlags.Instance)))), Nothing, list.ToArray, Nothing)
                        If ((Not info3 Is Nothing) AndAlso TypeProvider.IsAssignable(method.ReturnType, info3.ReturnType)) Then
                            flag = True
                        End If
                    End If
                End If
                If Not flag Then
                    Dim item As New ValidationError(SR.GetString("Error_CantResolveEventHandler", New Object() { dependencyProperty.Name, [TryCast](propValue,String) }), &H60F) { _
                        .PropertyName = MyBase.GetFullPropertyName(manager) _
                    }
                    errors.Add(item)
                End If
            End If
            Return errors
        End Function

    End Class
End Namespace

